package com.hhyx.execl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hhyx.execl.handler.BusinessException;
import com.hhyx.execl.mapper.SystemMessageMapper;
import com.hhyx.execl.mapper.UserDetailMapper;
import com.hhyx.execl.model.entity.Before;
import com.hhyx.execl.model.entity.SystemMessage;
import com.hhyx.execl.model.entity.UserDetail;
import com.hhyx.execl.model.params.SystemSearchParam;
import com.hhyx.execl.model.result.ReadFileResult;
import com.hhyx.execl.model.result.ReturnPage;
import com.hhyx.execl.service.BeforeFileService;
import com.hhyx.execl.service.SystemMessageService;
import com.hhyx.execl.util.ListUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author MarkerCCC
 * @date 2019/6/14 - 10:58
 * @email markerccc@163.com
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings("all")
public class SystemMessageServiceImpl extends
        ServiceImpl<SystemMessageMapper, SystemMessage> implements
        SystemMessageService {

    //0代表正在处理 1代表处理成功  2 代表处理失败
    private int flag = 0;
    private List<Map<String, Object>> out;

    private final BeforeFileService beforeFileService;

    private final SystemMessageMapper systemMessageMapper;

    private final UserDetailMapper userDetailMapper;


    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    public SystemMessageServiceImpl(
            BeforeFileService beforeFileService, SystemMessageMapper systemMessageMapper,
            UserDetailMapper userDetailMapper) {
        this.beforeFileService = beforeFileService;
        this.systemMessageMapper = systemMessageMapper;
        this.userDetailMapper = userDetailMapper;
    }

    @Override
    public void readFolder(HttpServletResponse httpServletResponse) {
        flag = 0;
        String pathStr = "D:\\MarkWork\\first";
        Date date = new Date();
        String localDateStr = LocalDate.now().toString();
        try {
            ArrayList<Map<String, Object>> mapArrayList = new ArrayList<>(10);
            readFile(pathStr, localDateStr, mapArrayList, httpServletResponse);
            List<Before> befores = new ArrayList<>(10);

            // 进行属性赋值
            mapArrayList.forEach(stringObjectMap -> {
                Before before = BeanUtil.mapToBean(stringObjectMap, Before.class, true);
                before.setCreateTime(date)
                        .setUpdateTime(date)
                        .setVersion(0)
                        .setDelFlag(0)
                        .setBatchNumber(localDateStr)
                        .set下辖ID(StrUtil.cleanBlank(before.get下辖ID()));
                before.setId(0L);
                befores.add(before);
            });

            // 开始遍历, 比对有没有重复数据
            Map<String, Object> allRepeatedElements = ListUtils
                    .findAllRepeatedElements(mapArrayList);

            ArrayList<Map<String, Object>> streamList = new ArrayList<>(10);
            ArrayList<String> fileList = new ArrayList<>(10);
            allRepeatedElements.entrySet().forEach(entry -> {
                // 这里拿到的都是文件名
                if ("file".equals(entry.getKey())) {
                    Set<String> value = (Set<String>) entry.getValue();
                    // 做遍历删除操作?, 根据
                    fileList.addAll(value);
                }
                Object value = entry.getValue();
                HashMap<String, Object> streamMap = new HashMap<>(16);
                streamMap.put("fileMessage", value.toString());
                streamList.add(streamMap);
            });

            if (CollectionUtils.isNotEmpty(streamList)) {
                // 生成流, 返回execl
                out = streamList;
                flag = 2;
            } else {
                flag = 1;
            }

            LinkedList<SystemMessage> systemMessageList = new LinkedList<>();

            // 进行插入操作, 这里逻辑错误
            if (CollectionUtils.isNotEmpty(fileList)) {
                // 也是进行全量插入, 但是要进行删除标识的处理

                befores.forEach(before -> {
                    SystemMessage systemMessage = new SystemMessage();
                    BeanUtil.copyProperties(before, systemMessage);
                    if (systemMessage.get下辖ID().length() != 7) {
                        String errorStr =
                                "文件: " + before.getFileName() + "的 " + before.get下辖ID()
                                        + " id不完整, 请重新填写";
                        systemMessage.setError(errorStr).setDelFlag(1);
                    }
                    systemMessage.setId(0L);
                    systemMessageList.add(systemMessage);
                });
                this.verifyExistence(systemMessageList);
                Set<String> fileSet = new HashSet<>(fileList);
                systemMessageList.stream()
                        .filter(systemMessage -> StrUtil.isNotBlank(systemMessage.getError()))
                        .forEach(systemMessage -> {
                            fileSet.add(systemMessage.getFileName());
                        });
                fileSet.forEach(fileStr -> {
                    // 在fileList里面的, 都标记为删除状态
                    systemMessageList.stream()
                            .filter(before1 -> fileStr.equals(before1.getFileName()))
                            .forEach(before2 -> {
                                before2.setDelFlag(1);
                            });
                });

            } else {
                befores.forEach(before -> {
                    SystemMessage systemMessage = new SystemMessage();
                    if (before.get下辖ID().length() != 7) {
                        String errorStr =
                                "文件: " + before.getFileName() + "的 " + before.get下辖ID()
                                        + " id不完整, 请重新填写";
                        systemMessage.setError(errorStr);
                    }

                    BeanUtil.copyProperties(before, systemMessage);
                    systemMessage.setId(0L);
                    systemMessageList.add(systemMessage);
                });
                this.verifyExistence(systemMessageList);
            }

            beforeFileService.saveBatch(befores);

            this.saveBatch(systemMessageList, 1000);
        } catch (IOException e) {
            flag = 0;
            log.error("{0}", e);
        }
    }

    /**
     * 验证用户信息是否存在
     *
     * @param systemMessageList
     */
    @Override
    public void verifyExistence(LinkedList<SystemMessage> systemMessageList) {
        ArrayList<String> strings = new ArrayList<>(10);
        systemMessageList.stream().forEach(systemMessage -> {
            strings.add(systemMessage.get下辖ID());
        });
        ArrayList<UserDetail> userDetails = new ArrayList<>(10);
        LinkedList<String> strings1 = new LinkedList<>();
        for (int i = 0; i < strings.size(); i++) {
            if (i % 1000 == 0 || i == strings.size() - 1) {
                strings1.add(strings.get(i));
                QueryWrapper<UserDetail> userDetailQueryWrapper = new QueryWrapper<>();
                userDetailQueryWrapper.select("店铺编号");
                userDetailQueryWrapper.in("店铺编号", strings1);
                List<UserDetail> userDetails1 = userDetailMapper.selectList(userDetailQueryWrapper);
                userDetails.addAll(userDetails1);
                strings1.clear();
            } else {
                strings1.add(strings.get(i));
            }
        }

        systemMessageList.forEach(systemMessage -> {
            List<String> userDetailsFieldList = userDetails.stream()
                    .map(userDetail -> userDetail.get店铺编号())
                    .collect(Collectors.toList());
            if (!userDetailsFieldList.contains(systemMessage.get下辖ID())) {
                String error = systemMessage.getError();
                StringBuilder errorBuilder;
                if (null == error) {
                    errorBuilder = new StringBuilder();
                    errorBuilder
                            .append("文件: " + systemMessage.getFileName() + "下辖ID: " + systemMessage
                                    .get下辖ID() + "不存在与userDetail中");
                } else {
                    errorBuilder = new StringBuilder(error);
                    errorBuilder.append("\t. 下辖ID: " + systemMessage.get下辖ID() + "不存在与userDetail中");
                }
                String errorStr = errorBuilder.toString();
                systemMessage.setError(errorStr).setDelFlag(1);
            }
        });
    }

    @Override
    public ReturnPage<SystemMessage> pageList(SystemSearchParam param) {
        Page<SystemMessage> page = new Page(param.getPage(), param.getLimit());
        List<SystemMessage> list = systemMessageMapper.pageList(page, param);
        ReturnPage<SystemMessage> rs = new ReturnPage();
        rs.setTotal(page.getTotal());
        rs.setRecords(list);
        return rs;
    }

    @Override
    public Integer getResult(HttpServletResponse response) {
        return flag;
    }

    @Override
    public ServletOutputStream getResult1(HttpServletResponse response) {
        ReadFileResult rs = new ReadFileResult();
        ExcelWriter writer = ExcelUtil.getBigWriter();
        writer.addHeaderAlias("fileMessage", "文件信息");
        writer.write(out, true);
        log.error("-------->{}", out.toString());
        writer.setColumnWidth(-1, 15);
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx");
        ServletOutputStream servletOutputStream = null;
        try {
            servletOutputStream = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.flush(servletOutputStream);
        writer.close();
        IoUtil.close(servletOutputStream);

        return servletOutputStream;
    }

    public void readFile(String pathStr, String localDateStr,
            ArrayList<Map<String, Object>> mapArrayList, HttpServletResponse response)
            throws IOException {
        List<File> files = new ArrayList<>(10);
        Files.walkFileTree(Paths.get(pathStr), new SimpleFileVisitor<Path>() {
            // 是文件夹继续
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                    throws IOException {
                return FileVisitResult.CONTINUE;
            }

            // 是文件进行处理
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                    throws IOException {
                // threadPoolExecutor.execute(() -> {
                    String name = file.toFile().getName();
                    String substring1 = name.substring(0, 2);
                    String substring = name.substring(name.lastIndexOf('.') + 1);
                    if (substring.contains("xl") && !substring1.contains("~$")) {
                        files.add(file.toFile());
                    }
                // });
                return super.visitFile(file, attrs);
            }

        });
        log.error("----->{}", files.size());
        files.forEach(file -> {
            // 使用HuTool读取Execl, 先进行单个execl验证, 多条通过sql去验证
            ExcelReader reader = null;
            try {
                reader = ExcelUtil.getReader(file);
            } catch (Exception e) {
                log.error("{}", e.getMessage());
                log.error("fileName: ----------------->{}", file.getName());
                throw new BusinessException("文件被占用, 进程无法访问");
            }
            List<Object> objects = reader.readRow(0);

            // 拿到了所有的内容, 包括表头, 这里没一行都是一个Map
            List<Map<String, Object>> maps = reader.readAll();

            int icount = 0;
            for (Map<String, Object> map : maps) {
                if (!map.containsKey("下辖ID")) {
                    log.error("------------------------------->{}", file.getName());
                    throw new BusinessException("缺少下辖ID列");
                }
                // 处理数据
                map.put("fileName", file.getName());
                map.put("row", icount);
                mapArrayList.add(map);
                log.error("{}", mapArrayList.size());
                ++icount;
            }
        });
    }

}
